/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package fotoxop;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Arrays;
import javax.swing.JOptionPane;
import sun.misc.Sort;

/**
 *
 * @author Paulo Ricardo
 */
public class ProcessamentoFotoXop {

    public ProcessamentoFotoXop() {
    }

    /*
     Negativo - Inversão de cores
     */
    public static BufferedImage Negativo(BufferedImage ImagemAtual) {

        //Variaveis
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        Color cor = null;

        //Pega o tamanho da Imagem - Largura x Altura
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        //Declaro um objeto de uma imagem / Sera a nova imagem
        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        //Percorre cada pixel da imagem fazendo a alteração
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                //Pega a cor Atual
                cor = new Color(ImagemAtual.getRGB(x, y));

                //Pega os Valores de RGB e ja faz a inversão
                Vermelho = (255 - cor.getRed());
                Azul = (255 - cor.getBlue());
                Verde = (255 - cor.getGreen());

                //Define a nova color com os valores invertidos anteriormente
                cor = new Color(Vermelho, Verde, Azul);

                //altera no pixel atual o novo RGB
                ImagemProcessada.setRGB(x, y, cor.getRGB());
            }
        }
        //Retorna a imagem processada
        return ImagemProcessada;
    }

    /*
     Quantização - Altera os pixels para valores mais discretos
     */
    public static BufferedImage Quantizacao(BufferedImage ImagemAtual, int level) {

        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        Color cor = null;

        double niveldecinza = 256.0;

        int intervalo_faixa = (int) Math.rint(niveldecinza / level);

        ArrayList<Integer> faixa = new ArrayList<Integer>();

        for (int i = 0; i < level; i++) {

            faixa.add(intervalo_faixa * i);
        }

        faixa.add(255);
        faixa.add(256);

        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);
        try {
            for (int y = 0; y < Height; y++) {
                for (int x = 0; x < Width; x++) {

                    cor = new Color(ImagemAtual.getRGB(x, y));

                    try {

                        for (int i = 0; i < level; i++) {

                            if ((cor.getRed() >= faixa.get(i)) && (cor.getRed() < faixa.get(i + 1))) {
                                Vermelho = faixa.get(i);
                            }

                            if ((cor.getBlue() >= faixa.get(i)) && (cor.getBlue() < faixa.get(i + 1))) {
                                Azul = faixa.get(i);
                            }

                            if ((cor.getGreen() >= faixa.get(i)) && (cor.getGreen() < faixa.get(i + 1))) {
                                Verde = faixa.get(i);
                            }

                            // se for o ultimo for
                            // Caso do 255
                        }

                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                    cor = new Color(Vermelho, Verde, Azul);
                    ImagemProcessada.setRGB(x, y, cor.getRGB());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ImagemProcessada;
    }

    /*
     Logaritmo - Clareamento da imagem
     Pega os pixels mais escuros e os altera para valores mais claros.
     Isso também ocorre em toda a imagem independente do nivel de cinza.
     Mas os valores mais escuros são mais afetados.
     */
    public static BufferedImage Logaritmo(BufferedImage ImagemAtual) {

        //Variaveis
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;

        //Escala para log base 10
        // Escala * LOG( 1 + 255) = 255
        // Escala = 255 / LOG(256) = 105,88
        //Escala definida para log na base 10
        double Escala = 105.88;

        Color cor = null;

        //Tamanho da imagem - Largura x Altura
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        //Declaro um objeto de uma imagem / Sera a nova imagem
        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        //Percorre cada pixel da imagem fazendo a alteração
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                //Pega a cor Atual
                cor = new Color(ImagemAtual.getRGB(x, y));

                //Pega os Valores de RGB fazendo as alterações
                /*
                 s = log(1 + r)
                 sendo r ≥ 0
                 */
                Vermelho = (int) Math.round(Escala * ((Math.log10(cor.getRed() + 1))));
                Azul = (int) Math.round(Escala * ((Math.log10(cor.getBlue() + 1))));
                Verde = (int) Math.round(Escala * ((Math.log10(cor.getGreen() + 1))));

                //Nova cor do pixel
                cor = new Color(Vermelho, Verde, Azul);

                //Altera o piexel atual como a nova cor
                ImagemProcessada.setRGB(x, y, cor.getRGB());
            }
        }
        //Retorna a nova imagem
        return ImagemProcessada;
    }

    /*
     AntiLogaritmo - Inverso do Log
     Pega os pixels mais claros e os altera para valores mais escuros.
     Isso também ocorre em toda a imagem independente do nivel de cinza.
     Mas os valores mais claros são mais afetados.
     */
    public static BufferedImage AntiLogaritmo(BufferedImage ImagemAtual) {

        //Variaveis
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        Color cor = null;

        //Escala definida para log na base 10
        double Escala = 105.88;

        //Tamanho da imagem - Largura x Altura
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        //Declaro um objeto de uma imagem / Sera a nova imagem
        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        //Percorre cada pixel da imagem fazendo a alteração
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                //Pega a cor atual
                cor = new Color(ImagemAtual.getRGB(x, y));

                //Pega os Valores de RGB fazendo as alterações
                /*
                 S = base^(r/s)
                 sendo base considerada 10, r é o nivel e s é a escala utilizada
                 */
                // o valor 10 é porque é na base 10
                Vermelho = (int) Math.round(Math.pow(10, (cor.getRed() / Escala)));
                Azul = (int) Math.round(Math.pow(10, (cor.getBlue() / Escala)));
                Verde = (int) Math.round(Math.pow(10, (cor.getGreen() / Escala)));

                try {
                    //Nova cor do pixel
                    cor = new Color(Vermelho, Verde, Azul);
                } catch (Exception e) {
                    e.printStackTrace();
                }

                //Altera o piexel atual como a nova cor
                ImagemProcessada.setRGB(x, y, cor.getRGB());
            }
        }
        //Retorna a nova imagem
        return ImagemProcessada;
    }

    /*
     Potencia - Transformação que leva em consideração um valor definido
     O valor do GAMA que ira definir como sera a transformação
     */
    public static BufferedImage Potencia(BufferedImage ImagemAtual, double Gama) {

        //Variaveis
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        double r;
        double L = 255.0;
        int Constante = 1;
        Color cor = null;

        //Tamanho da imagem - Largura x Altura
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        //Declaro um objeto de uma imagem / Sera a nova imagem
        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        //Percorre cada pixel da imagem fazendo a alteração
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                //Pega a cor Atual
                cor = new Color(ImagemAtual.getRGB(x, y));

                // Pega os Valores de RGB fazendo as alterações
                /*
                 s = cr^Y
                 c é a constante definida acima como 1
                 r nivel atual divido pelo nivel final
                 Y Gama - Definido pelo Usuario 
                 Y < 1 - Clareamento
                 Y > 1 - Escurecimento
                 Y = 1 - Identidade
                 */
                r = cor.getRed() / L;
                Vermelho = (int) (Constante * (L * ((Math.pow(r, Gama)))));

                r = cor.getBlue() / L;
                Azul = (int) (Constante * ((L * (Math.pow(r, Gama)))));

                r = cor.getGreen() / L;
                Verde = (int) (Constante * ((L * (Math.pow(r, Gama)))));

                //Nova cor do Pixel
                cor = new Color(Vermelho, Verde, Azul);

                //Altera o pixel atual como a nova cor
                ImagemProcessada.setRGB(x, y, cor.getRGB());
            }
        }
        //Retorna a nova imagem
        return ImagemProcessada;
    }

    /*
     Raiz -  Transformação que leva em consideração um valor definido.
     O valor do GAMA que ira definir como sera a transformação
     */
    public static BufferedImage Raiz(BufferedImage ImagemAtual, double Gama) {

        //Variaveis
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        double L = 255.0;
        double r;
        int Constante = 1;
        Color cor = null;

        //Tamanho da imagem - Largura x Altura
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        //Declaro um objeto de uma imagem / Sera a nova imagem
        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        //Percorre cada pixel da imagem fazendo a alteração
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                //Pega a cor Atual
                cor = new Color(ImagemAtual.getRGB(x, y));

                // Pega os Valores de RGB fazendo as alterações
                /*
                 s = cl(r^(1/Y))
                 c é a constante definida acima como 1
                 l nivel final
                 r nivel atual divido pelo nivel final
                 Y Gama - Definido pelo Usuario 
                 Y < 1 - Escurecimento
                 Y > 1 - Clareamento
                 Y = 1 - Identidade
                 */
                r = cor.getRed() / L;
                double Potencia = Math.pow(r, (1 / Gama));
                Vermelho = (int) (Constante * (L * (Math.pow(r, (1 / Gama)))));

                r = cor.getBlue() / L;
                Azul = (int) (Constante * ((L * Math.pow(r, (1 / Gama)))));

                r = cor.getGreen() / L;
                Verde = (int) (Constante * ((L * Math.pow(r, (1 / Gama)))));

                //Nova cor do Pixel
                cor = new Color(Vermelho, Verde, Azul);

                //Altera o pixel atual como a nova cor
                ImagemProcessada.setRGB(x, y, cor.getRGB());

            }
        }
        //Retorna a nova imagem
        return ImagemProcessada;
    }

    /*
     Espelhamento Horizontal
     Tem o objetivo de refletir a imagem em torno do eixo y
     Preserva distâncias e inverte o sentido dos ângulos preservando seu valor absoluto
     */
    public static BufferedImage EspelhamentoHorizontal(BufferedImage ImagemAtual) {

        //Tamanho da imagem - Largura x Altura 
        int TamanhodaImagem = ImagemAtual.getHeight() - 1;
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        Color cor;

        //Declaro um objeto de uma imagem / Sera a nova imagem
        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        //Percorre cada pixel da imagem fazendo a alteração
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                //Cor atual do pixel
                cor = new Color(ImagemAtual.getRGB(x, y));

                try {
                    //Faz alteração do pixel atual
                    /*
                     Permanece o valor da coordenada de y e altera a de x
                     Movendo o pixel de lugar
                     */
                    ImagemProcessada.setRGB(TamanhodaImagem - x, y, cor.getRGB());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        //Retorna a nova imagem
        return ImagemProcessada;
    }

    /*
     Rotação 90° - Anti Horario
            
     */
    public static BufferedImage RotacaoAntiHorario90(BufferedImage ImagemAtual) {

        //Tamanho da imagem - Largura x Altura
        int TamanhodaImagem = (ImagemAtual.getHeight() - 1);
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        Color cor;

        //Declaro um objeto de uma imagem / Sera a nova imagem
        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        try {
            //Percorre cada pixel da imagem fazendo a alteração
            for (int y = 0; y < ImagemAtual.getHeight(); y++) {
                for (int x = 0; x < ImagemAtual.getWidth(); x++) {

                    //Cor atual do pixel
                    cor = new Color(ImagemAtual.getRGB(x, y));
                    //Variavel de controle
                    int rgb = cor.getRGB();
                    //Fazendo a rotação na nova imagem
                    /*
                        
                     */
                    ImagemProcessada.setRGB(y, TamanhodaImagem - x, rgb);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        //Retorno da imagem alterada
        return ImagemProcessada;
    }

    /*
     Rotação 90° - Horario
            
     */
    public static BufferedImage RotacaoHorario90(BufferedImage ImagemAtual) {

        //Tamanho da imagem - Largura x Altura
        int TamanhodaImagem = (ImagemAtual.getHeight() - 1);
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        Color cor;

        //Declaro um objeto de uma imagem / Sera a nova imagem
        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        //Percorre cada pixel da imagem fazendo a alteração
        for (int y = 0; y < ImagemAtual.getHeight(); y++) {
            for (int x = 0; x < ImagemAtual.getWidth(); x++) {

                //Cor atual do pixel
                cor = new Color(ImagemAtual.getRGB(x, y));
                //Variavel de controle
                int rgb = cor.getRGB();
                //Fazendo a rotação na nova imagem
                    /*
                        
                 */
                ImagemProcessada.setRGB(TamanhodaImagem - y, x, rgb);
            }
        }
        //Retorno da imagem alterada
        return ImagemProcessada;
    }

    public static BufferedImage Rotacao180(BufferedImage ImagemAtual) {

        //Tamanho da imagem - Largura x Altura
        int TamanhodaImagem = (ImagemAtual.getHeight() - 1);
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();
        Color cor;

        //Declaro um objeto de uma imagem / Sera a nova imagem
        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        //Percorre cada pixel da imagem fazendo a alteração
        for (int y = 0; y < ImagemAtual.getHeight(); y++) {
            for (int x = 0; x < ImagemAtual.getWidth(); x++) {

                //Cor atual do pixel
                cor = new Color(ImagemAtual.getRGB(x, y));
                //Variavel de controle
                int rgb = cor.getRGB();
                //Fazendo a rotação na nova imagem
                    /*
                        
                 */
                ImagemProcessada.setRGB(TamanhodaImagem - x, TamanhodaImagem - y, rgb);
            }
        }
        //Retorno da imagem alterada
        return ImagemProcessada;
    }

    /*
     Espelhamento Vertical
     Tem o objetivo de refletir a imagem em torno do eixo x
     Preserva distâncias e inverte o sentido dos ângulos preservando seu valor absoluto
     */
    public static BufferedImage EspelhamentoVertical(BufferedImage ImagemAtual) {

        //Tamanho da imagem - Largura x Altura
        int TamanhodaImagem = ImagemAtual.getWidth() - 1;
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        Color cor;

        //Declaro um objeto de uma imagem / Sera a nova imagem
        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        //Percorre cada pixel da imagem fazendo a alteração
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                // Cor atual do pixel
                cor = new Color(ImagemAtual.getRGB(x, y));
                // Faz a alteração do pixel na nova imagem
                ImagemProcessada.setRGB(x, TamanhodaImagem - y, cor.getRGB());
            }
        }
        //Retorno da imagem alterada
        return ImagemProcessada;
    }

    public static BufferedImage Amostragem(BufferedImage ImagemAtual, int Mascara) {

        double Amostra = 0;
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        int rgb = 0;
        Color cor = null;

        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        // Percorre a Imagem
        for (int y = 0; y < Height; y = y + Mascara) {
            for (int x = 0; x < Width; x = x + Mascara) {

                // Zera o RGB
                Vermelho = 0;
                Azul = 0;
                Verde = 0;

                // Somatorio da Mascara para média
                for (int my = y; my < (y + Mascara); my++) {
                    for (int mx = x; mx < (x + Mascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx <= Height) && (my <= Width)) {

                            cor = new Color(ImagemAtual.getRGB(my, mx));
                            Vermelho = Vermelho + cor.getRed();
                            Verde = Verde + cor.getGreen();
                            Azul = Azul + cor.getBlue();
                        }
                    }
                }

                try {
                    Amostra = Mascara * Mascara;

                    Vermelho = (int) Math.ceil(Vermelho / Amostra);
                    Verde = (int) Math.ceil(Verde / Amostra);
                    Azul = (int) Math.ceil(Azul / Amostra);

                    cor = new Color(Vermelho, Verde, Azul);

                    rgb = cor.getRGB();

                } catch (Exception e) {

                    e.printStackTrace();
                }
                for (int my = y; my < (y + Mascara); my++) {
                    for (int mx = x; mx < (x + Mascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx <= Height) && (my <= Width)) {

                            ImagemProcessada.setRGB(my, mx, rgb);
                        }
                    }
                }
            }
        }
        return ImagemProcessada;
    }

    /*
    
    
    
    
     SEGUNDA PARTE DO TRABALHO PRATICO (2)
    
    
    
    
     */
    public static BufferedImage Media(BufferedImage ImagemAtual, int parametro) {

        double Media = 0;
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        int rgb = 0;
        Color cor = null;

        // só aceita mascara Par
        if (parametro % 2 == 0) {
            parametro++;
        }
        int Mascara = (int) Math.floor(parametro / 2);

        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        // Percorre a Imagem
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                // Zera o RGB
                Vermelho = 0;
                Azul = 0;
                Verde = 0;

                // Somatorio da Mascara para média
                for (int my = (y - Mascara); my <= (y + Mascara); my++) {
                    for (int mx = (x - Mascara); mx <= (x + Mascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx < Height) && (my < Width)) {

                            cor = new Color(ImagemAtual.getRGB(my, mx));
                            Vermelho = Vermelho + cor.getRed();
                            Verde = Verde + cor.getGreen();
                            Azul = Azul + cor.getBlue();
                        }
                    }
                }
                try {
                    Media = parametro * parametro;

                    Vermelho = (int) Math.ceil(Vermelho / Media);
                    Verde = (int) Math.ceil(Verde / Media);
                    Azul = (int) Math.ceil(Azul / Media);

                    cor = new Color(Vermelho, Verde, Azul);

                    rgb = cor.getRGB();

                } catch (Exception e) {
                    e.printStackTrace();
                }
                ImagemProcessada.setRGB(y, x, rgb);
            }
        }
        return ImagemProcessada;
    }

    public static BufferedImage Mediaana(BufferedImage ImagemAtual, int parametro) {

        double Media = 0;
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        int rgb = 0;
        Color cor = null;

        // só aceita mascara Par
        if (parametro % 2 == 0) {
            parametro++;
        }
        int Mascara = (int) Math.floor(parametro / 2);

        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        int TamanhoVetor = parametro * parametro;

        int[] Listvermelho = new int[TamanhoVetor];
        int[] Listverde = new int[TamanhoVetor];
        int[] Listazul = new int[TamanhoVetor];

        int contador = 0;

        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        // Percorre a Imagem
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                // Zera o RGB
                Vermelho = 0;
                Azul = 0;
                Verde = 0;

                for (int my = (y - Mascara); my <= (y + Mascara); my++) {
                    for (int mx = (x - Mascara); mx <= (x + Mascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx < Height) && (my < Width)) {

                            cor = new Color(ImagemAtual.getRGB(my, mx));

                            Listvermelho[contador] = cor.getRed();
                            Listverde[contador] = cor.getGreen();
                            Listazul[contador] = cor.getBlue();
                            contador++;
                        }
                    }
                }
                contador = 0;
                try {
                    Media = parametro * parametro;

                    Arrays.sort(Listvermelho);
                    Arrays.sort(Listverde);
                    Arrays.sort(Listazul);

                    int posicaocentral = (int) Math.floor((parametro * parametro) / 2);

                    cor = new Color(Listvermelho[posicaocentral], Listverde[posicaocentral], Listazul[posicaocentral]);

                    rgb = cor.getRGB();

                } catch (Exception e) {
                    e.printStackTrace();
                }
                ImagemProcessada.setRGB(y, x, rgb);
            }
        }
        return ImagemProcessada;
    }

    public static BufferedImage Moda(BufferedImage ImagemAtual, int Mascara) {

        double Moda = 0;
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        int rgb = 0;
        Color cor = null;

        // parametro define a máscara =  parametro X parametro
        // só aceita mascara Ímpar
        if (Mascara % 2 == 0) {
            Mascara++;
        }

        // Variavel para ajudar na hora de percorrer a mascara
        int LimiteDaMascara = (int) Math.floor(Mascara / 2);

        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        int TamanhoVetor = Mascara * Mascara;

        int[] Listvermelho = new int[TamanhoVetor];
        int[] Listverde = new int[TamanhoVetor];
        int[] Listazul = new int[TamanhoVetor];

        int contador = 0;

        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        // Percorre a Imagem
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                // Percorre a Mascara
                for (int my = (y - LimiteDaMascara); my <= (y + LimiteDaMascara); my++) {
                    for (int mx = (x - LimiteDaMascara); mx <= (x + LimiteDaMascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx < Height) && (my < Width)) {

                            cor = new Color(ImagemAtual.getRGB(my, mx));

                            Listvermelho[contador] = cor.getRed();
                            Listverde[contador] = cor.getGreen();
                            Listazul[contador] = cor.getBlue();
                            contador++;
                        } else {

                            cor = new Color(0, 0, 0);

                            Listvermelho[contador] = cor.getRed();
                            Listverde[contador] = cor.getGreen();
                            Listazul[contador] = cor.getBlue();
                            contador++;
                        }
                    }
                }
                contador = 0;
                try {

                    // Variaveis que armazenaram o valor da moda
                    int ModaVermelho = 0;
                    int ModaVerde = 0;
                    int ModaAzul = 0;

                    // Variaveis que guardam o número de aparecimentos de determinado valor
                    int AparecimentosVermelho = 0;
                    int AparecimentosVerde = 0;
                    int AparecimentosAzul = 0;

                    // Armazena o numero de vezes que a moda atual apareceu
                    int AparecimentosModaAtualVermelho = 0;
                    int AparecimentosModaAtualVerde = 0;
                    int AparecimentosModaAtualAzul = 0;

                    // Armazena o valor que será analisado
                    int TempValorVermelho = 0;
                    int TempValorVerde = 0;
                    int TempValorAzul = 0;

                    // Percorre cada valor dos vetores indentificando o número de vezes
                    // que cada valor aparece e definindo a moda.
                    for (int q = 0; q < TamanhoVetor; q++) {
                        //Define qual valor será analisado
                        TempValorVermelho = Listvermelho[q];
                        TempValorVerde = Listverde[q];
                        TempValorAzul = Listazul[q];

                        // Verifica o numero de vezes que aquela valor aparece no vetor
                        for (int w = 0; w < TamanhoVetor; w++) {

                            if (TempValorVermelho == Listvermelho[w]) {
                                AparecimentosVermelho++;
                            }

                            if (TempValorVerde == Listverde[w]) {
                                AparecimentosVerde++;
                            }

                            if (TempValorAzul == Listazul[w]) {
                                AparecimentosAzul++;
                            }

                        }

                        // Verifica se existe uma nova moda
                        if (AparecimentosVermelho > AparecimentosModaAtualVermelho) {
                            ModaVermelho = TempValorVermelho;
                            AparecimentosModaAtualVermelho = AparecimentosVermelho;
                            AparecimentosVermelho = 0;
                        }

                        if (AparecimentosVerde > AparecimentosModaAtualVerde) {
                            ModaVerde = TempValorVerde;
                            AparecimentosModaAtualVerde = AparecimentosVerde;
                            AparecimentosVerde = 0;
                        }

                        if (AparecimentosAzul > AparecimentosModaAtualAzul) {
                            ModaAzul = TempValorAzul;
                            AparecimentosModaAtualAzul = AparecimentosAzul;
                            AparecimentosAzul = 0;
                        }

                    }

                    cor = new Color(ModaVermelho, ModaVerde, ModaAzul);

                    rgb = cor.getRGB();

                } catch (Exception e) {
                    e.printStackTrace();
                }
                ImagemProcessada.setRGB(y, x, rgb);
            }
        }
        return ImagemProcessada;
    }

    public static BufferedImage Min(BufferedImage ImagemAtual, int Mascara) {

        double Moda = 0;
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        int rgb = 0;
        Color cor = null;

        // parametro define a máscara =  parametro X parametro
        // só aceita mascara Ímpar
        if (Mascara % 2 == 0) {
            Mascara++;
        }

        // Variavel para ajudar na hora de percorrer a mascara
        int LimiteDaMascara = (int) Math.floor(Mascara / 2);

        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        int TamanhoVetor = Mascara * Mascara;

        int[] Listvermelho = new int[TamanhoVetor];
        int[] Listverde = new int[TamanhoVetor];
        int[] Listazul = new int[TamanhoVetor];

        int contador = 0;

        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        // Percorre a Imagem
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                // Percorre a Mascara
                for (int my = (y - LimiteDaMascara); my <= (y + LimiteDaMascara); my++) {
                    for (int mx = (x - LimiteDaMascara); mx <= (x + LimiteDaMascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx < Height) && (my < Width)) {

                            cor = new Color(ImagemAtual.getRGB(my, mx));

                            Listvermelho[contador] = cor.getRed();
                            Listverde[contador] = cor.getGreen();
                            Listazul[contador] = cor.getBlue();
                            contador++;
                        } else {

                            cor = new Color(0, 0, 0);

                            Listvermelho[contador] = cor.getRed();
                            Listverde[contador] = cor.getGreen();
                            Listazul[contador] = cor.getBlue();
                            contador++;
                        }
                    }
                }
                contador = 0;
                try {

                    // Variaveis que armazenaram o valor do minimo
                    int MinVermelho = 300;
                    int MinVerde = 300;
                    int MinAzul = 300;

                    // Armazena o valor que será analisado
                    int TempValorVermelho = 0;
                    int TempValorVerde = 0;
                    int TempValorAzul = 0;

                    // Percorre cada valor dos vetores indentificando o menor valor
                    for (int q = 0; q < TamanhoVetor; q++) {

                        //Define qual valor será analisado
                        TempValorVermelho = Listvermelho[q];
                        TempValorVerde = Listverde[q];
                        TempValorAzul = Listazul[q];

                        //se ele for menor que o minimo atual, ele será o novo minimo
                        if (TempValorVermelho < MinVermelho) {
                            MinVermelho = TempValorVermelho;
                        }

                        if (TempValorVerde < MinVerde) {
                            MinVerde = TempValorVerde;
                        }

                        if (TempValorAzul < MinAzul) {
                            MinAzul = TempValorAzul;
                        }

                    }

                    cor = new Color(MinVermelho, MinVerde, MinAzul);

                    rgb = cor.getRGB();

                } catch (Exception e) {
                    e.printStackTrace();
                }
                ImagemProcessada.setRGB(y, x, rgb);
            }
        }
        return ImagemProcessada;
    }

    public static BufferedImage Max(BufferedImage ImagemAtual, int Mascara) {

        double Moda = 0;
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        int rgb = 0;
        Color cor = null;

        // parametro define a máscara =  parametro X parametro
        // só aceita mascara Ímpar
        if (Mascara % 2 == 0) {
            Mascara++;
        }

        // Variavel para ajudar na hora de percorrer a mascara
        int LimiteDaMascara = (int) Math.floor(Mascara / 2);

        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        int TamanhoVetor = Mascara * Mascara;

        int[] Listvermelho = new int[TamanhoVetor];
        int[] Listverde = new int[TamanhoVetor];
        int[] Listazul = new int[TamanhoVetor];

        int contador = 0;

        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        // Percorre a Imagem
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                // Percorre a Mascara
                for (int my = (y - LimiteDaMascara); my <= (y + LimiteDaMascara); my++) {
                    for (int mx = (x - LimiteDaMascara); mx <= (x + LimiteDaMascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx < Height) && (my < Width)) {

                            cor = new Color(ImagemAtual.getRGB(my, mx));

                            Listvermelho[contador] = cor.getRed();
                            Listverde[contador] = cor.getGreen();
                            Listazul[contador] = cor.getBlue();
                            contador++;
                        } else {

                            cor = new Color(0, 0, 0);

                            Listvermelho[contador] = cor.getRed();
                            Listverde[contador] = cor.getGreen();
                            Listazul[contador] = cor.getBlue();
                            contador++;
                        }
                    }
                }
                contador = 0;
                try {

                    // Variaveis que armazenaram o valor do max
                    int MaxVermelho = -1;
                    int MaxVerde = -1;
                    int MaxAzul = -1;

                    // Armazena o valor que será analisado
                    int TempValorVermelho = 0;
                    int TempValorVerde = 0;
                    int TempValorAzul = 0;

                    // Percorre cada valor dos vetores indentificando o maior valor
                    for (int q = 0; q < TamanhoVetor; q++) {

                        //Define qual valor será analisado
                        TempValorVermelho = Listvermelho[q];
                        TempValorVerde = Listverde[q];
                        TempValorAzul = Listazul[q];

                        //se ele for maior que o maximo atual, ele será o novo maximo
                        if (TempValorVermelho > MaxVermelho) {
                            MaxVermelho = TempValorVermelho;
                        }

                        if (TempValorVerde > MaxVerde) {
                            MaxVerde = TempValorVerde;
                        }

                        if (TempValorAzul > MaxAzul) {
                            MaxAzul = TempValorAzul;
                        }

                    }

                    cor = new Color(MaxVermelho, MaxVerde, MaxAzul);

                    rgb = cor.getRGB();

                } catch (Exception e) {
                    e.printStackTrace();
                }
                ImagemProcessada.setRGB(y, x, rgb);
            }
        }
        return ImagemProcessada;
    }

    public static double[] HistogramaEqualizado(BufferedImage ImagemAtual, String Tipo){
        
        int TamanhoImagem = ImagemAtual.getWidth() * ImagemAtual.getHeight();
        int NivelDeCinza = 256;
        
        //pegam os niveis de cada pixel e colocam em um vetor
        double vetorvermelho[] = getNCsImagem(ImagemAtual,"R");
        double vetorverde[] = getNCsImagem(ImagemAtual,"G");
        double vetorazul[] = getNCsImagem(ImagemAtual,"B");
        
        //Vetor para armazenar a frequencia dos niveis de cinza
        double VetorFrequenciaVermelho[] = new double[NivelDeCinza];
        double VetorFrequenciaVerde[] = new double[NivelDeCinza];
        double VetorFrequenciaAzul[] = new double[NivelDeCinza];
        
        //Vetor que armazena a nova frequencia
        double VetorNovaFrequenciaVermelho[] = new double[NivelDeCinza];
        double VetorNovaFrequenciaVerde[] = new double[NivelDeCinza];
        double VetorNovaFrequenciaAzul[] = new double[NivelDeCinza];
        
        //vetor que armazena os novos niveis de cinza
        int VetorNovosNiveisVermelho[] = new int[NivelDeCinza];
        int VetorNovosNiveisVerde[] = new int[NivelDeCinza];
        int VetorNovosNiveisAzul[] = new int[NivelDeCinza];
        
        //vetor que armazena o somatorio da frequencia
        double SomatorioVermelho[] = new double[NivelDeCinza];
        double SomatorioVerde[] = new double[NivelDeCinza];
        double SomatorioAzul[] = new double[NivelDeCinza];
        
        int repopulacao = 0;
        
        
        
        //verifica a frequencia dos niveis de cinza e popula os vetores de frequencia
        for(int nc = 0; nc < NivelDeCinza; nc++){
            for(int i = 0; i < TamanhoImagem; i++){
                if (vetorvermelho[i] == nc){
                    VetorFrequenciaVermelho[nc] = VetorFrequenciaVermelho[nc] + 1;                 
                }
                
                if (vetorverde[i] == nc){
                    VetorFrequenciaVerde[nc] = VetorFrequenciaVerde[nc] + 1;                 
                }
                
                if (vetorazul[i] == nc){
                    VetorFrequenciaAzul[nc] = VetorFrequenciaAzul[nc] + 1;                 
                }
                       
            }
            
            // quantidade de pixels do nc especifico dividio pelo total de pixels da imagem
            VetorFrequenciaVermelho[nc] = VetorFrequenciaVermelho[nc] / TamanhoImagem;
            VetorFrequenciaVerde[nc] = VetorFrequenciaVerde[nc] / TamanhoImagem;
            VetorFrequenciaAzul[nc] = VetorFrequenciaAzul[nc] / TamanhoImagem;
        }
        
        //Faz o somatorio das frequencias
        SomatorioVermelho[0] = VetorFrequenciaVermelho[0];
        SomatorioVerde[0] = VetorFrequenciaVerde[0];
        SomatorioAzul[0] = VetorFrequenciaAzul[0];
        
        for(int i = 1;i < NivelDeCinza; i++){
            SomatorioVermelho[i] = VetorFrequenciaVermelho[i] + SomatorioVermelho[i - 1];
            SomatorioVerde[i] = VetorFrequenciaVerde[i] + SomatorioVerde[i - 1];
            SomatorioAzul[i] = VetorFrequenciaAzul[i] + SomatorioAzul[i - 1];
        }
        
        //comparar o somatorio com os niveis de cinza para transformação
        
        for(int i = 0; i < NivelDeCinza; i++){
            VetorNovosNiveisVermelho[i] = i;
            VetorNovosNiveisVerde[i] = i;
            VetorNovosNiveisAzul[i] = i;
            
            double DiferencaVermelho = Math.abs(SomatorioVermelho[i] - i);
            double DiferencaVerde = Math.abs(SomatorioVerde[i] - i);
            double DiferencaAzul = Math.abs(SomatorioAzul[i] - i);
            
            
            for(int nc = 1; nc < NivelDeCinza; nc++){
                if( (Math.abs(SomatorioVermelho[i] - nc)) < DiferencaVermelho ){
                    VetorNovosNiveisVermelho[i] = nc;
                    DiferencaVermelho = Math.abs(SomatorioVermelho[i] - nc);
                }
                
                if( (Math.abs(SomatorioVerde[i] - nc)) < DiferencaVerde ){
                    VetorNovosNiveisVerde[i] = nc;
                    DiferencaVerde = Math.abs(SomatorioVerde[i] - nc);
                }
                
                if( (Math.abs(SomatorioAzul[i] - nc)) < DiferencaAzul ){
                    VetorNovosNiveisAzul[i] = nc;
                    DiferencaAzul = Math.abs(SomatorioAzul[i] - nc);
                }
            } 
            
            
        }
        
        // Qual sera a nova frequencia dos niveis de cinza?
        for(int i = 0; i < NivelDeCinza; i++){
            
            double SumVermelho = 0;
            double SumVerde = 0;
            double SumAzul = 0;                   
                    
            for(int nc = 0; nc < NivelDeCinza; nc++){
                //se o nível da posição nc for igual a i
                if(VetorNovosNiveisVermelho[nc] == i){
                    SumVermelho = SumVermelho + VetorFrequenciaVermelho[nc];                  
                }   
                
                if(VetorNovosNiveisVerde[nc] == i){
                    SumVermelho = SumVermelho + VetorFrequenciaVermelho[nc];                  
                }  
                
                if(VetorNovosNiveisAzul[nc] == i){
                    SumVermelho = SumVermelho + VetorFrequenciaVermelho[nc];                  
                }  
            }
            
                // A nova frequencia do nivel i será:
                VetorNovaFrequenciaVermelho[i] = SumVermelho;
                VetorNovaFrequenciaVerde[i] = SumVerde;
                VetorNovaFrequenciaAzul[i] = SumAzul;
        }
        
        for(int i=0;i<NivelDeCinza;i++){
            VetorNovaFrequenciaVermelho[i] = VetorNovaFrequenciaVermelho[i] * TamanhoImagem;
            VetorNovaFrequenciaVerde[i] = VetorNovaFrequenciaVerde[i] * TamanhoImagem;
            VetorNovaFrequenciaAzul[i] = VetorNovaFrequenciaAzul[i] * TamanhoImagem;
        }
        
        //Geração dos vetores com os niveis de cada pixel da imagem
        
        for(int i = 0; i < TamanhoImagem; i++){
            for(int j = 0; j < VetorNovaFrequenciaVermelho[i]; j++){
                vetorvermelho[repopulacao] = i;
                repopulacao++;
            }
        }
        
        repopulacao = 0;
        for(int i = 0; i < TamanhoImagem; i++){
            for(int j = 0; j < VetorNovaFrequenciaVerde[i]; j++){
                vetorverde[repopulacao] = i;
                repopulacao++;
            }
        }
        
       repopulacao = 0;
       for(int i = 0; i < TamanhoImagem; i++){
            for(int j = 0; j < VetorNovaFrequenciaAzul[i]; j++){
                vetorazul[repopulacao] = i;
                repopulacao++;
            }
        }
        
        if (Tipo.equals("R")) {
            return vetorvermelho;
        } else if (Tipo.equals("G")) {
            return vetorverde;
        } else {
            return vetorazul;
        }        
        
    }
    
    public static double[] getNCsImagem(BufferedImage ImagemAtual, String Tipo) {
        int TamanhoImagem = ImagemAtual.getWidth() * ImagemAtual.getHeight();
        double vermelho[] = new double[TamanhoImagem];
        double verde[] = new double[TamanhoImagem];
        double azul[] = new double[TamanhoImagem];
        int contador = 0;
        Color cor;

        for (int y = 0; y < ImagemAtual.getHeight(); y++) {
            for (int x = 0; x < ImagemAtual.getWidth(); x++) {
                cor = new Color(ImagemAtual.getRGB(y, x));
                vermelho[contador] = cor.getRed();
                verde[contador] = cor.getGreen();
                azul[contador] = cor.getBlue();
                contador++;
            }

        }

        if (Tipo.equals("R")) {
            return vermelho;
        } else if (Tipo.equals("G")) {
            return verde;
        } else {
            return azul;
        }
    }

    public static BufferedImage SomarImagens(BufferedImage Imagem1, BufferedImage Imagem2, float Porcent1, float Porcent2) {

        Color cor1;
        Color cor2;
        Color cor;
        BufferedImage ImagemProcessada = new BufferedImage(Imagem1.getWidth(), Imagem1.getHeight(), BufferedImage.TYPE_INT_RGB);

        int Vermelho;
        int Verde;
        int Azul;
        int rgb;

        Porcent1 = Porcent1 / 100;
        Porcent2 = Porcent2 / 100;

        for (int y = 0; y < Imagem1.getHeight(); y++) {
            for (int x = 0; x < Imagem1.getWidth(); x++) {

                cor1 = new Color(Imagem1.getRGB(y, x));
                cor2 = new Color(Imagem2.getRGB(y, x));
                int red = cor1.getRed();

                int red1 = Math.round(cor1.getRed() * Porcent1);
                int red2 = Math.round(cor2.getRed() * Porcent2);

                Vermelho = red1 + red2;

                int verde1 = Math.round(cor1.getGreen() * Porcent1);
                int verde2 = Math.round(cor2.getGreen() * Porcent2);

                Verde = verde1 + verde2;

                int azul1 = Math.round(cor1.getBlue() * Porcent1);
                int azul2 = Math.round(cor2.getBlue() * Porcent2);

                Azul = azul1 + azul2;

                if (Vermelho > 255) {
                    Vermelho = 255;
                }
                if (Verde > 255) {
                    Verde = 255;
                }

                if (Azul > 255) {
                    Azul = 255;
                }

                cor = new Color(Vermelho, Verde, Azul);

                rgb = cor.getRGB();

                ImagemProcessada.setRGB(y, x, rgb);

            }

        }

        return ImagemProcessada;

    }

    public static BufferedImage Expansao(BufferedImage Imagem1, int a, int b) {

        Color cor1;
        Color cor2;
        Color cor;
        BufferedImage ImagemProcessada = new BufferedImage(Imagem1.getWidth(), Imagem1.getHeight(), BufferedImage.TYPE_INT_RGB);

        int Vermelho;
        int Verde;
        int Azul;
        int rgb;

        for (int y = 0; y < Imagem1.getHeight(); y++) {
            for (int x = 0; x < Imagem1.getWidth(); x++) {

                cor1 = new Color(Imagem1.getRGB(y, x));

                Vermelho = (a * cor1.getRed()) + b;

                Verde = (a * cor1.getGreen()) + b;

                Azul = (a * cor1.getBlue()) + b;

                if (Vermelho > 255) {
                    Vermelho = 255;
                }
                if (Verde > 255) {
                    Verde = 255;
                }

                if (Azul > 255) {
                    Azul = 255;
                }

                cor = new Color(Vermelho, Verde, Azul);

                rgb = cor.getRGB();

                ImagemProcessada.setRGB(y, x, rgb);

            }

        }

        return ImagemProcessada;

    }

    public static BufferedImage Compressao(BufferedImage Imagem1, int a, int b) {

        Color cor1;
        Color cor2;
        Color cor;
        BufferedImage ImagemProcessada = new BufferedImage(Imagem1.getWidth(), Imagem1.getHeight(), BufferedImage.TYPE_INT_RGB);

        int Vermelho;
        int Verde;
        int Azul;
        int rgb;

        for (int y = 0; y < Imagem1.getHeight(); y++) {
            for (int x = 0; x < Imagem1.getWidth(); x++) {

                cor1 = new Color(Imagem1.getRGB(y, x));

                Vermelho = (int) (cor1.getRed()) / a - b;

                Verde = (int) (cor1.getGreen()) / a - b;

                Azul = (int) (cor1.getBlue()) / a - b;

                if (Vermelho < 0) {
                    Vermelho = 0;
                }
                if (Verde < 0) {
                    Verde = 0;
                }

                if (Azul < 0) {
                    Azul = 0;
                }

                cor = new Color(Vermelho, Verde, Azul);

                rgb = cor.getRGB();

                ImagemProcessada.setRGB(y, x, rgb);

            }

        }

        return ImagemProcessada;

    }

    public static BufferedImage Prewit(BufferedImage ImagemAtual) {

        double Media = 0;
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        int rgb = 0;
        Color cor = null;

        int parametro = 3;

        // só aceita mascara Par
        if (parametro % 2 == 0) {
            parametro++;
        }
        int Mascara = (int) Math.floor(parametro / 2);

        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        // Percorre a Imagem
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                // Zera o RGB
                Vermelho = 0;
                Azul = 0;
                Verde = 0;

                int i = 0;
                int j = 0;
                int[][] MatrizVermelho = new int[3][3];
                int[][] MatrizVerde = new int[3][3];
                int[][] MatrizAzul = new int[3][3];
                for (int my = (y - Mascara); my <= (y + Mascara); my++) {

                    for (int mx = (x - Mascara); mx <= (x + Mascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx < Height) && (my < Width)) {

                            cor = new Color(ImagemAtual.getRGB(my, mx));
                            Vermelho = cor.getRed();
                            Verde = cor.getGreen();
                            Azul = cor.getBlue();

                            MatrizVermelho[i][j] = Vermelho;
                            MatrizVerde[i][j] = Verde;
                            MatrizAzul[i][j] = Azul;

                        }
                        j = j + 1;
                    }
                    j = 0;
                    i = i + 1;
                }

                int[][] FiltroH = {
                    {-1, -1, -1},
                    {0, 0, 0},
                    {1, 1, 1}
                };

                int[][] FiltroV = {
                    {-1, 0, 1},
                    {-1, 0, 1},
                    {-1, 0, 1}
                };

                int[][] MatrizVermelhoH = new int[3][3];
                int[][] MatrizVerdeH = new int[3][3];
                int[][] MatrizAzulH = new int[3][3];

                int[][] MatrizVermelhoV = new int[3][3];
                int[][] MatrizVerdeV = new int[3][3];
                int[][] MatrizAzulV = new int[3][3];

                // for para aplicação multiplicação das matrizes H
                for (int k = 0; k < 3; k++) {
                    for (int l = 0; l < 3; l++) {

                        MatrizVermelhoH[k][l] = MatrizVermelho[k][l] * FiltroH[k][l];
                        MatrizVerdeH[k][l] = MatrizVerde[k][l] * FiltroH[k][l];
                        MatrizAzulH[k][l] = MatrizAzul[k][l] * FiltroH[k][l];

                        MatrizVermelhoV[k][l] = MatrizVermelho[k][l] * FiltroV[k][l];
                        MatrizVerdeV[k][l] = MatrizVerde[k][l] * FiltroV[k][l];
                        MatrizAzulV[k][l] = MatrizAzul[k][l] * FiltroV[k][l];
                    }
                }

                int VermelhoH = 0;
                int AzulH = 0;
                int VerdeH = 0;

                int VermelhoV = 0;
                int AzulV = 0;
                int VerdeV = 0;

                // for da soma dos pixels
                for (int k = 0; k < 3; k++) {

                    VermelhoH += MatrizVermelhoH[0][k] + MatrizVermelhoH[2][k];
                    VerdeH += MatrizVerdeH[0][k] + MatrizVerdeH[2][k];
                    AzulH += MatrizAzulH[0][k] + MatrizAzulH[2][k];

                    VermelhoV += MatrizVermelhoV[0][k] + MatrizVermelhoV[2][k];
                    VerdeV += MatrizVerdeV[0][k] + MatrizVerdeV[2][k];
                    AzulV += MatrizAzulV[0][k] + MatrizAzulV[2][k];
                }

                Vermelho = Math.abs(VermelhoH) + Math.abs(VermelhoV);
                Verde = Math.abs(VerdeH) + Math.abs(VerdeV);
                Azul = Math.abs(AzulH) + Math.abs(AzulV);

                try {

                    if (Vermelho < 0) {
                        Vermelho = 0;
                    } else if (Vermelho > 255) {
                        Vermelho = 255;
                    }

                    if (Verde < 0) {
                        Verde = 0;
                    } else if (Verde > 255) {
                        Verde = 255;
                    }

                    if (Azul < 0) {
                        Azul = 0;
                    } else if (Azul > 255) {
                        Azul = 255;
                    }

                    cor = new Color(Vermelho, Verde, Azul);

                    rgb = cor.getRGB();

                } catch (Exception e) {
                    e.printStackTrace();
                }
                ImagemProcessada.setRGB(y, x, rgb);
            }
        }
        return ImagemProcessada;

    }

    public static BufferedImage Sobel(BufferedImage ImagemAtual) {

        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        int rgb = 0;
        Color cor = null;

        int parametro = 3;

        // só aceita mascara Par
        if (parametro % 2 == 0) {
            parametro++;
        }
        int Mascara = (int) Math.floor(parametro / 2);

        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);

        // Percorre a Imagem
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                // Zera o RGB
                Vermelho = 0;
                Azul = 0;
                Verde = 0;

                int i = 0;
                int j = 0;
                int[][] MatrizVermelho = new int[3][3];
                int[][] MatrizVerde = new int[3][3];
                int[][] MatrizAzul = new int[3][3];

                for (int my = (y - Mascara); my <= (y + Mascara); my++) {

                    for (int mx = (x - Mascara); mx <= (x + Mascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx < Height) && (my < Width)) {

                            cor = new Color(ImagemAtual.getRGB(my, mx));
                            Vermelho = cor.getRed();
                            Verde = cor.getGreen();
                            Azul = cor.getBlue();

                            MatrizVermelho[i][j] = Vermelho;
                            MatrizVerde[i][j] = Verde;
                            MatrizAzul[i][j] = Azul;

                        }
                        j = j + 1;
                    }
                    j = 0;
                    i = i + 1;
                }

                int[][] FiltroH = {
                    {-1, -2, -1},
                    {0, 0, 0},
                    {1, 2, 1}
                };

                int[][] FiltroV = {
                    {-1, 0, 1},
                    {-2, 0, 2},
                    {-1, 0, 1}
                };

                int[][] MatrizVermelhoH = new int[3][3];
                int[][] MatrizVerdeH = new int[3][3];
                int[][] MatrizAzulH = new int[3][3];

                int[][] MatrizVermelhoV = new int[3][3];
                int[][] MatrizVerdeV = new int[3][3];
                int[][] MatrizAzulV = new int[3][3];

                // for para aplicação multiplicação das matrizes H
                for (int k = 0; k < 3; k++) {
                    for (int l = 0; l < 3; l++) {

                        MatrizVermelhoH[k][l] = MatrizVermelho[k][l] * FiltroH[k][l];
                        MatrizVerdeH[k][l] = MatrizVerde[k][l] * FiltroH[k][l];
                        MatrizAzulH[k][l] = MatrizAzul[k][l] * FiltroH[k][l];

                        MatrizVermelhoV[k][l] = MatrizVermelho[k][l] * FiltroV[k][l];
                        MatrizVerdeV[k][l] = MatrizVerde[k][l] * FiltroV[k][l];
                        MatrizAzulV[k][l] = MatrizAzul[k][l] * FiltroV[k][l];
                    }
                }

                int VermelhoH = 0;
                int AzulH = 0;
                int VerdeH = 0;

                int VermelhoV = 0;
                int AzulV = 0;
                int VerdeV = 0;

                // for da soma dos pixels
                for (int k = 0; k < 3; k++) {

                    VermelhoH += MatrizVermelhoH[0][k] + MatrizVermelhoH[2][k];
                    VerdeH += MatrizVerdeH[0][k] + MatrizVerdeH[2][k];
                    AzulH += MatrizAzulH[0][k] + MatrizAzulH[2][k];

                    VermelhoV += MatrizVermelhoV[0][k] + MatrizVermelhoV[2][k];
                    VerdeV += MatrizVerdeV[0][k] + MatrizVerdeV[2][k];
                    AzulV += MatrizAzulV[0][k] + MatrizAzulV[2][k];
                }

                Vermelho = Math.abs(VermelhoH) + Math.abs(VermelhoV);
                Verde = Math.abs(VerdeH) + Math.abs(VerdeV);
                Azul = Math.abs(AzulH) + Math.abs(AzulV);

                try {

                    if (Vermelho < 0) {
                        Vermelho = 0;
                    } else if (Vermelho > 255) {
                        Vermelho = 255;
                    }

                    if (Verde < 0) {
                        Verde = 0;
                    } else if (Verde > 255) {
                        Verde = 255;
                    }

                    if (Azul < 0) {
                        Azul = 0;
                    } else if (Azul > 255) {
                        Azul = 255;
                    }

                    cor = new Color(Vermelho, Verde, Azul);

                    rgb = cor.getRGB();

                } catch (Exception e) {
                    e.printStackTrace();
                }
                ImagemProcessada.setRGB(y, x, rgb);
            }
        }
        return ImagemProcessada;

    }
    
    public static BufferedImage Scale2x(BufferedImage ImagemAtual){
        
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        int rgb = 0;
        int rgb0 = 0;
        int rgb1 = 0;
        int rgb2 = 0;
        int rgb3 = 0;
        Color cor = null;
        Color cor0 = null;
        Color cor1 = null;
        Color cor2 = null;
        Color cor3 = null;
        
        int Parametro = 3;
        int Mascara = (int) Math.floor(Parametro / 2);
        
        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();
        
        BufferedImage ImagemProcessada = new BufferedImage(Width * 2, Height * 2, BufferedImage.TYPE_INT_RGB);
        
        
        // Percorre a Imagem
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {
                   
                 // Zera o RGB
                Vermelho = 0;
                Azul = 0;
                Verde = 0;

                int i = 0;
                int j = 0;
                
                // mascaras
                int[][] MatrizVermelho = new int[Parametro][Parametro];
                int[][] MatrizVerde = new int[Parametro][Parametro];
                int[][] MatrizAzul = new int[Parametro][Parametro];

                
                for (int my = (y - Mascara); my <= (y + Mascara); my++) {

                    for (int mx = (x - Mascara); mx <= (x + Mascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx < Height) && (my < Width)) {

                            cor = new Color(ImagemAtual.getRGB(my, mx));
                            Vermelho = cor.getRed();
                            Verde = cor.getGreen();
                            Azul = cor.getBlue();    
                            
                            MatrizVermelho[i][j] = Vermelho;
                            MatrizVerde[i][j] = Verde;
                            MatrizAzul[i][j] = Azul;
                        }
                        
                        j = j + 1;
                    }
                    j = 0;
                    i = i + 1;
                }
                
                int Avermelho = MatrizVermelho[0][0];
                int Averde = MatrizVerde[0][0];
                int Aazul = MatrizAzul[0][0];
                
                int Bvermelho = MatrizVermelho[0][1];
                int Bverde = MatrizVerde[0][1];
                int Bazul = MatrizAzul[0][1];
                
                int Cvermelho = MatrizVermelho[0][2];
                int Cverde = MatrizVerde[0][2];
                int Cazul = MatrizAzul[0][2];
                
                int Dvermelho = MatrizVermelho[1][0];
                int Dverde = MatrizVerde[1][0];
                int Dazul = MatrizAzul[1][0];
                
                int Evermelho = MatrizVermelho[1][1];
                int Everde = MatrizVerde[1][1];
                int Eazul = MatrizAzul[1][1];
                
                int Fvermelho = MatrizVermelho[1][2];
                int Fverde = MatrizVerde[1][2];
                int Fazul = MatrizAzul[1][2];
                
                int Gvermelho = MatrizVermelho[2][0];
                int Gverde = MatrizVerde[2][0];
                int Gazul = MatrizAzul[2][0];
                
                int Hvermelho = MatrizVermelho[2][1];
                int Hverde = MatrizVerde[2][1];
                int Hazul = MatrizAzul[2][1];
                
                int Ivermelho = MatrizVermelho[2][2];
                int Iverde = MatrizVerde[2][2];
                int Iazul = MatrizAzul[2][2];
                
                int E0vermelho, E0verde, E0azul;
                int E1vermelho, E1verde, E1azul;
                int E2vermelho, E2verde, E2azul;
                int E3vermelho, E3verde, E3azul;
                
                if (Bvermelho != Hvermelho && Dvermelho != Fvermelho) {
                    E0vermelho = Dvermelho == Bvermelho ? Dvermelho : Evermelho;
                    E1vermelho = Bvermelho == Fvermelho ? Fvermelho : Evermelho;
                    E2vermelho = Dvermelho == Hvermelho ? Dvermelho : Evermelho;
                    E3vermelho = Hvermelho == Fvermelho ? Fvermelho : Evermelho;
                } 
                
                else {
                    E0vermelho = Evermelho;
                    E1vermelho = Evermelho;
                    E2vermelho = Evermelho;
                    E3vermelho = Evermelho;
                }
                
                if (Bverde != Hverde && Dverde != Fverde) {
                    E0verde = Dverde == Bverde ? Dverde : Everde;
                    E1verde = Bverde == Fverde ? Fverde : Everde;
                    E2verde = Dverde == Hverde ? Dverde : Everde;
                    E3verde = Hverde == Fverde ? Fverde : Everde;
                } 
                
                else {
                    E0verde = Everde;
                    E1verde = Everde;
                    E2verde = Everde;
                    E3verde = Everde;
                }
                
                if (Bazul != Hazul && Dazul != Fazul) {
                    E0azul = Dazul == Bazul ? Dazul : Eazul;
                    E1azul = Bazul == Fazul ? Fazul : Eazul;
                    E2azul = Dazul == Hazul ? Dazul : Eazul;
                    E3azul = Hazul == Fazul ? Fazul : Eazul;
                } 
                
                else {
                    E0azul = Eazul;
                    E1azul = Eazul;
                    E2azul = Eazul;
                    E3azul = Eazul;
                }
                
                
                
                cor0 = new Color(E0vermelho, E0verde, E0azul);
                cor1 = new Color(E1vermelho, E1verde, E1azul);
                cor2 = new Color(E2vermelho, E2verde, E2azul);
                cor3 = new Color(E3vermelho, E3verde, E3azul);
                
                
                rgb0 = cor0.getRGB();
                rgb1 = cor1.getRGB();
                rgb2 = cor2.getRGB();
                rgb3 = cor3.getRGB();
                
                ImagemProcessada.setRGB(y * 2, x * 2, rgb0);
                ImagemProcessada.setRGB(y * 2 + 1, x * 2, rgb1);
                ImagemProcessada.setRGB(y * 2, x * 2 + 1, rgb2);
                ImagemProcessada.setRGB(y * 2 + 1, x * 2 + 1, rgb3);
                
                
            }
        }
        return ImagemProcessada;
        
        
    }

    public static BufferedImage DesfoqueGaussiano(BufferedImage ImagemAtual,int parametro) {

        
        int Vermelho = 0;
        int Azul = 0;
        int Verde = 0;
        int rgb = 0;
        Color cor = null;

        // só aceita mascara impar
        if (parametro % 2 == 0) {
            parametro++;
        }
        int Mascara = (int) Math.floor(parametro / 2);

        int Width = ImagemAtual.getWidth();
        int Height = ImagemAtual.getHeight();

        BufferedImage ImagemProcessada = new BufferedImage(Width, Height, BufferedImage.TYPE_INT_RGB);
        
        
        double [][] MatrizPesos = new double[parametro][parametro];
        
        
        // Marcara de Pesos
        // definido desvio padrão como 1.5
        double Soma = 0;
        int y1 = 1;        
        for (int i = 0; i < parametro; i++) {
            int x1 = -1;
            
            for (int j = 0; j < parametro; j++) {
                
                MatrizPesos[i][j] = (1/((2*(3.14))*1.5*1.5) * Math.exp(-((x1*x1)+(y1*y1))/(2*(1.5*1.5))));
                Soma = Soma + MatrizPesos[i][j];
                x1++;
            }
            
            y1--;
        }
        
        
        // for para ajuste dos pesos
        for (int i = 0; i < parametro; i++) {
                      
            for (int j = 0; j < parametro; j++) {
                
                MatrizPesos[i][j] = MatrizPesos[i][j]/Soma;
       
              
            }
     
        }
        
       
        // Percorre a Imagem
        for (int y = 0; y < Height; y++) {
            for (int x = 0; x < Width; x++) {

                // Zera o RGB
                Vermelho = 0;
                Azul = 0;
                Verde = 0;

                int i = 0;
                int j = 0;
                
                // mascaras
                double[][] MatrizVermelho = new double[parametro][parametro];
                double[][] MatrizVerde = new double[parametro][parametro];
                double[][] MatrizAzul = new double[parametro][parametro];

                for (int my = (y - Mascara); my <= (y + Mascara); my++) {

                    for (int mx = (x - Mascara); mx <= (x + Mascara); mx++) {

                        if ((my >= 0) && (mx >= 0) && (mx < Height) && (my < Width)) {

                            cor = new Color(ImagemAtual.getRGB(my, mx));
                            Vermelho = cor.getRed();
                            Verde = cor.getGreen();
                            Azul = cor.getBlue();

                            
                            // aplica o filtro de desfoque
                            MatrizVermelho[i][j] = Vermelho*MatrizPesos[i][j];
                            MatrizVerde[i][j] = Verde*MatrizPesos[i][j];
                            MatrizAzul[i][j] = Azul*MatrizPesos[i][j];
                            
                            

                        }
                        j = j + 1;
                    }
                    j = 0;
                    i = i + 1;
                }
                
                Vermelho = 0;
                Verde = 0;
                Azul = 0;
                
                
                // somatorio dos pixels da mascara
                for (int k = 0; k < parametro; k++) {
                    for (int l = 0; l < parametro; l++) {
                        
                        Vermelho = (int) (Vermelho + Math.round(MatrizVermelho[k][l]));
                        Verde = (int) (Verde + Math.round(MatrizVerde[k][l]));
                        Azul = (int) (Azul + Math.round(MatrizAzul[k][l]));
                        
                    }
                }
                
                
                
                try {
                   
                    // teste de limites
                    
                     if (Vermelho < 0) {
                        Vermelho = 0;
                    } else if (Vermelho > 255) {
                        Vermelho = 255;
                    }

                    if (Verde < 0) {
                        Verde = 0;
                    } else if (Verde > 255) {
                        Verde = 255;
                    }

                    if (Azul < 0) {
                        Azul = 0;
                    } else if (Azul > 255) {
                        Azul = 255;
                    }
                    
                    
                    cor = new Color(Vermelho, Verde, Azul);

                    rgb = cor.getRGB();

                } catch (Exception e) {
                    e.printStackTrace();
                }
                ImagemProcessada.setRGB(y, x, rgb);
            }
        }
        
        
        return ImagemProcessada;
    }
    }